from typing import List, overload
import os
import sys

import chardet
import jieba
from numpy.lib.utils import source
# print(os.getcwd())
# print(sys.path)
# sys.path.append("d:\\数据智能研究中心\\项目\\zzst2\\workflow4threeman\\workflow")
# print(sys.path)

from workflow.Configuration import STATE, TextAnalyzerAlgorithm

from workflow.TextPayLoad import TextPayLoad
from workflow.TextAnalyzer.base_analyzer import BaseAnalyzer, BaseAnalyzerConfig

from gensim.test.utils import common_texts
from gensim.corpora.dictionary import Dictionary
from gensim.models import LdaModel

class LdaAnalyzerConfig(BaseAnalyzerConfig):
    TYPE: str = "LDA"
    
    def __init__(
        self, 
        algorithm: str=TextAnalyzerAlgorithm.LDA.Algorithm.DEFAULT, 
        topics: int=100, 
        alpha: float=0.5,
        beta: float=0.1,
        iter: int=2000
    ) -> None:
        """
        实例化LDA的config，设置一系列参数

        Args:
            algorithm (str, optional): LDA使用的算法，可选jGibbsLDA和gensim. Defaults to TextAnalyzerAlgorithm.LDA.Algorithm.DEFAULT.
            topics (int, optional): LDA中需要的主题数. Defaults to 100.
            alpha (float, optional): LDA的超参数，表示文档的主题稀疏程度，较高的alpha值代表主题分布更均匀. Defaults to 0.5.
            beta (float, optional): LDA的超参数，表示词的稀疏程度，较高的beta值代表文档包含大多数词. Defaults to 0.1.
            iter (int, optional): 迭代次数. Defaults to 2000.
        """
        
        super().__init__()
        if algorithm in TextAnalyzerAlgorithm.LDA.Algorithm.__dict__.values():
            self.algorithm = algorithm
        # else:
        #     return ""                
        self.topics = topics
        self.alpha = alpha
        self.beta = beta
        self.iter = iter
        
        
class JGibbsLDA(BaseAnalyzer):
    """
    JGibbsLDA的实现，通过命令行调用JGibbsLDA进行计算
    该包需要对文件进行操作，因此需要先将传入的文档保存为临时文件，而后删除
    """
    
    def __init__(self, lda_config: LdaAnalyzerConfig):
        super().__init__()
        self.config = lda_config
    
    def save_temp_file(
        self,
        source_response: TextPayLoad
        ) -> None:
        """根据传入的文本保存临时的文件，需要组织为该包需要的格式

        Args:
            source_response (TextPayLoad): 传入的文本类型数据
        """ 
        doc_nums = len(source_response.process_text)
        with open(TextAnalyzerAlgorithm.LDA.Model.JGibbsLDATempFilePath, 'w') as f:
            f.write(doc_nums)
            for text in source_response.process_text:
                f.write(" ".join(text) + "\n")
        
    def analyze(
        self, 
        source_response: TextPayLoad, 
        **kwargs
    ) -> TextPayLoad:
        self.save_temp_file(source_response)
        """
        首先切换到以该包为根目录的位置
        如果存在已经训练好的模型，则进行增量训练，否则从头训练
        """ 
        if os.path.exists(TextAnalyzerAlgorithm.LDA.Model.JGibbsLDAPackagePath):
            os.chdir(TextAnalyzerAlgorithm.LDA.Model.JGibbsLDAPackagePath)
        
        """
            增量训练
        """
        public_command = "java -mx512M -cp bin:lib/args4j-2.0.6.jar jgibblda.LDA"
        public_params = {
                "-alpha": self.config.alpha,
                "-beta": self.config.beta,
                "-ntopics": self.config.topics, 
                "-niters": self.config.iter,
                "-savestep": int(self.config.iter / 100),
                "-twords": 20,
                "-dfile": TextAnalyzerAlgorithm.LDA.Model.JGibbsLDATempFilePath
        }
        if os.path.exists(TextAnalyzerAlgorithm.LDA.Model.JGibbsLDAModelPath):
            command_params = " -estc"         
        else:
            command_params = " -est"
        
        """
            构建并执行当前命令
        """
        command = public_command + command_params
        for key, value in public_params.items():
            command = command + " " + key + " " + value + " "
        os.popen(cmd=command)
        
        """
            修改TextPayLoad的状态
        """
        source_response.state = STATE.TextAnalyzerState.LDA_Result
        source_response.success = True
        
        return source_response

class GensimLDA(BaseAnalyzer):
    def __init__(self, lda_config: LdaAnalyzerConfig):
        super().__init__()
        self.config = lda_config

    def analyze(self, 
    source_response: TextPayLoad, 
    **kwargs
    ) -> TextPayLoad:
        """
        gensim常规流程
        """
        common_texts: List[List[str]]
        common_texts = list()

        #def splited texts function
        stopwords_list = list()
        f = open('workflow/TextAnalyzer/stopwords.txt','r',encoding='utf-8')
        line = f.readline()
        while line:
            stopwords_list.append(line.strip())
            line = f.readline()
        for text in source_response.raw_text:
            temp_l = jieba.lcut(text,cut_all=False)
            for t in temp_l:
                if t in stopwords_list:
                    temp_l.remove(t)
            common_texts.append(temp_l)
        common_dictionary = Dictionary(common_texts)
        common_corpus = [common_dictionary.doc2bow(t) for t in common_texts]
        lda = LdaModel(common_corpus, num_topics=self.config.topics,id2word=common_dictionary)
        source_response.state = STATE.TextAnalyzerState.LDA_Result
        source_response.success = True

        return LdaModel.print_topics(lda,num_topics=3,num_words=10)


class LdaAnalyzer(BaseAnalyzer):
    TYPE: str = "LDA"    

    def __init__(self, lda_config: LdaAnalyzerConfig):
        super().__init__()
        self.config = lda_config
    
    def get_default_params(
        self, 
        source_response: TextPayLoad,
        **kwargs,
    ) -> LdaAnalyzerConfig:
        
        return self.config
    
    def analyze(
        self,
        source_response: TextPayLoad,
        **kwargs,
    ) -> TextPayLoad:
        
        """
        根据传入文档计算推荐的超参数，更新config中的设置
        """
        self.config = self.get_default_params(
            source_response
        )

        if self.config.algorithm == TextAnalyzerAlgorithm.LDA.Algorithm.DEFAULT:
            """
                根据算法参数选择某一个类
            """
            analyzer = JGibbsLDA(self.config)
            # print(analyzer.config)
        elif self.config.algorithm == TextAnalyzerAlgorithm.LDA.Algorithm.GENSIM:
            analyzer = GensimLDA(self.config)
            
        return analyzer.analyze(source_response)
# lda_config = LdaAnalyzerConfig()
# analyzer = LdaAnalyzer()